﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Globalization;

namespace HeightMapper
{
    public partial class Form1 : Form
    {
        public int Octaves = 4;
        public Dictionary<int, float> Frequency;
        public Dictionary<int, float> Amplitude;
        public int Seed = 0;
        public Form1()
        {
            Frequency = new Dictionary<int, float>();
            Amplitude = new Dictionary<int, float>();
            for (int o = 0; o < Octaves; o++)
            {
                Frequency.Add(o, 1f / (o + 1));
                Amplitude.Add(o, 2.0f*(o+1));
            }
            InitializeComponent();
            textBox1.Text = Seed.ToString();
            numericUpDown1.Value = Octaves;
            SetTabs(Octaves);
        }
        private void SetTabs(int q)
        {
            tabControl1.TabPages.Clear();
            for (int t = 0; t < q; t++)
            {
                string title = "Oct. " + (t);
                TabPage newtab = new TabPage(title);
                Label frq = new Label();
                frq.Text = "Freqüencia";
                frq.Location = new System.Drawing.Point(7, 7);
                frq.AutoSize = true;
                Label amp = new Label();
                amp.Text = "Ample";
                amp.Location = new System.Drawing.Point(11, 34);
                amp.AutoSize = true;
                TextBox tfrq = new NumericTextBox();
                tfrq.Text = Frequency[t].ToString();
                tfrq.Location = new System.Drawing.Point(74, 7);
                TextBox tamp = new NumericTextBox();
                tamp.Text = Amplitude[t].ToString();
                tamp.Location = new System.Drawing.Point(74, 34);
                newtab.Controls.Add(frq);
                newtab.Controls.Add(amp);
                newtab.Controls.Add(tfrq);
                newtab.Controls.Add(tamp);
                tabControl1.TabPages.Add(newtab);
            }
        }

               
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            int oldcount = Octaves;
            Octaves = (int)numericUpDown1.Value;
            Frequency.Clear();            
            Amplitude.Clear();
            int.TryParse(textBox1.Text,out Seed);
            for (int o = 0; o < Octaves; o++)
            {
                float f = 0;
                float a = 0;
                if (o < oldcount)
                {
                    float.TryParse(tabControl1.Controls[o].Controls[2].Text.ToString(), out f);
                    float.TryParse(tabControl1.Controls[o].Controls[3].Text.ToString(), out a);
                }
                else
                {
                    f = 1.0f/Frequency[o-1];
                    a = 2.0f*Amplitude[o-1];
                }
                Frequency.Add(o, f);
                Amplitude.Add(o, a);
            }
             
            SetTabs(Octaves);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Bitmap b = new Bitmap(pictureBox1.Width, pictureBox1.Height);
            Graphics gr = Graphics.FromImage(b);            
            progressBar1.Value = 0;
            progressBar1.Maximum = (pictureBox1.Height * pictureBox1.Width);

            for(int x = 0; x < pictureBox1.Width;x++)
                for (int y = 0; y < pictureBox1.Height; y++)
                {
                    float result = 0;
                    for (int o = 0; o < Octaves; o++)
                    {
                        result += SimplexNoise.Noise.Generate((x + Seed) * Amplitude[o], (y + Seed) * Amplitude[o]) * Frequency[o];
                    }
                    Color col = Color.FromArgb(ColorClamp(result),ColorClamp(result),ColorClamp(result));
                    SolidBrush brush = new SolidBrush(col);
                    Rectangle rec = new Rectangle(x, y, 1, 1);
                    gr.FillRectangle(brush, rec);
                        progressBar1.Value++;
                }
            pictureBox1.Image = b;

        }
        private int ColorClamp(float mul)
        {
            mul = Math.Abs(mul);

            if (mul < 0.0f)
                mul = 0.0f;
            if (mul > 1.0f)
                mul = 1.0f;
            return (int)(255.0f * mul);
        }
        private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (Char.IsDigit(e.KeyChar))
            {
                e.Handled = true;
            }
            else
            {
                e.Handled = false;
            }
        }

        private void quantAToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show(" LLuis Sanahuja. Copyright 2014 Apache 2.0\n ldsanahuja@gmail.com\n  SimplexNoise1234 by Stefan Gustavson \n ", "Quant a HeightMapper", 
                MessageBoxButtons.OK,
                MessageBoxIcon.Question);
        }

        private void ajudaToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show(" - La freqüencia son les repeticions del soroll en l'imatge\n - L'ample modifica la força del paràmetre final\n - L'arrel controla la aleatorietat\n - Octaves (1-10) es la quantitat de passis que farà\n - Aplicar sempre els canvis abans de generar",
                "Ajuda",
                MessageBoxButtons.OK, MessageBoxIcon.Question);
        }
    

    }

    //http://msdn.microsoft.com/en-us/library/ms229644(v=vs.90).aspx
    public class NumericTextBox : TextBox
    {
        bool allowSpace = false;

        // Restricts the entry of characters to digits (including hex), the negative sign, 
        // the decimal point, and editing keystrokes (backspace).
        // Modificat, només accepta decimal
        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            base.OnKeyPress(e);

            NumberFormatInfo numberFormatInfo = System.Globalization.CultureInfo.CurrentCulture.NumberFormat;
            string decimalSeparator = numberFormatInfo.NumberDecimalSeparator;
            string groupSeparator = numberFormatInfo.NumberGroupSeparator;
            string negativeSign = numberFormatInfo.NegativeSign;

            // Workaround for groupSeparator equal to non-breaking space 
            if (groupSeparator == ((char)160).ToString())
            {
                groupSeparator = " ";
            }

            string keyInput = e.KeyChar.ToString();

            if (Char.IsDigit(e.KeyChar))
            {
                // Digits are OK
            }
            else if (keyInput.Equals(decimalSeparator))
            {
                // Decimal separator is OK
            }
            else if (e.KeyChar == '\b')
            {
                // Backspace key is OK
            }
            else if (this.allowSpace && e.KeyChar == ' ')
            {

            }
            else
            {
                e.Handled = true;
            }
        }

        public int IntValue
        {
            get
            {
                return Int32.Parse(this.Text);
            }
        }

        public decimal DecimalValue
        {
            get
            {
                return Decimal.Parse(this.Text);
            }
        }

        public bool AllowSpace
        {
            set
            {
                this.allowSpace = value;
            }

            get
            {
                return this.allowSpace;
            }
        }
    }

}
